/**
 * Copyright (c) 2008, Mu Dynamics.
 *  All rights reserved.
 *  
 *   Redistribution and use in source and binary forms, with or without modification, 
 *   are permitted provided that the following conditions are met:
 *   
 *  - Redistributions of source code must retain the above copyright notice, 
 *     this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice, 
 *     this list of conditions and the following disclaimer in the documentation and/or 
 *     other materials provided with the distribution.
 *  - Neither the name of the "Mu Dynamics" nor the names of its contributors may be used 
 *     to endorse  or promote products derived from this software without specific prior 
 *     written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.mu.jacob.core.generator;

import java.util.Arrays;

import org.apache.log4j.Logger;

import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.mu.jacob.core.ant.ConfigModule;
import com.mu.jacob.core.builder.IBuilder;

/**
 * Jacob runner used for integration into a Java build app.
 * @author Adam Smyczek
 *
 */
public class JacobRunner {

	/* Element module */
	private ElementModule elementModule = new ElementModule();
	
	/* Custom module for Guice DI */
	private Module module = null;

	/**
	 * Element module setter
	 * @param module
	 */
	public void setElementModule(final ElementModule module) {
		this.elementModule = module;
	}
	
	/**
	 * Custom module setter
	 * @param module
	 */
	public void setCustomModule(final Module module) {
		this.module = module;
	}
	
	/**
	 * Run code generation
	 * @param modelSets containing all model classes
	 * @param builders list of builders
	 * @param classPath optional class path for the compiler processor
	 */
	public void run(final IBuilder[] builders, final String classPath, final ModelSet... modelSets) {
		
		logger.debug("Bootstrapping application");
		DecoratorModule decoratorModule = new DecoratorModule();
		ConfigModule configModule = new ConfigModule();
		Module customModule = (module != null)? module : emptyModule;
		Injector injector = Guice.createInjector(configModule, decoratorModule, elementModule, customModule);
		
		// Create configuration
		logger.debug("Configuring jacob");
		DefaultConfig config = (DefaultConfig)injector.getInstance(Config.class);
		config.initialize(injector);
		config.addModelSets(Arrays.asList(modelSets));
		// Set class path
		if (classPath != null) {
			config.setClassPath(classPath);
		}
		decoratorModule.setConfig(config);
		
		// Initialize builders
		for (IBuilder builder : builders) {
			injector.injectMembers(builder);
		}
		
		// Create and run processor
		logger.debug("Generating");
		JacobProcessor processor = injector.getInstance(JacobProcessor.class);
		processor.process(Arrays.asList(builders));
		
		logger.debug("Done");
	}
	
	/* Empty module */
	private final static Module emptyModule = new Module() { public void configure(Binder binder) { }};
	
	private static final Logger logger = Logger.getLogger(JacobRunner.class);
}
